#!/bin/bash
#===========================================================================================
# Function: Update the kernel for OpenWrt (Amlogic s9xxx, Allwinner, Rockchip)
# Copyright (C) 2020-- https://github.com/unifreq/openwrt_packit
# Copyright (C) 2021-- https://github.com/ophub/luci-app-amlogic
#===========================================================================================

# Support the kernel: boot-*.tar.gz, dtb-*.tar.gz, modules-*.tar .gz
# When the kernel version is upgraded from 5.10 or lower to 5.10 or higher, Amlogic s9xxx need to install U-BOOT.
# When there is no U-BOOT file in related directory, the script will auto try to download the file from the server:
# UBOOT_OVERLOAD: https://github.com/ophub/luci-app-amlogic/tree/main/depends/meson_btld/without_fip
# MAINLINE_UBOOT: https://github.com/ophub/luci-app-amlogic/tree/main/depends/meson_btld/with_fip

# The UBOOT_OVERLOAD and MAINLINE_UBOOT files download path
GITHUB_RAW="https://raw.githubusercontent.com/ophub/luci-app-amlogic/main/depends/meson_btld"

# Encountered a serious error, abort the script execution
die() {
    echo -e " [Error] ${1}"
    exit 1
}

echo -e "Start update the openwrt kernel."
# Operation environment check
[ -x /usr/sbin/openwrt-kernel ] || die "Please grant execution permission: chmod +x /usr/sbin/openwrt-kernel"

# Current device model
MYDEVICE_NAME=$(cat /proc/device-tree/model | tr -d '\000')
if [[ -z "${MYDEVICE_NAME}" ]]; then
    die "The device name is empty and cannot be recognized."
elif [[ "$(echo ${MYDEVICE_NAME} | grep "Chainedbox L1 Pro")" != "" ]]; then
    MYDTB_FILE="rockchip"
    MYBOOT_VMLINUZ="Image"
elif [[ "$(echo ${MYDEVICE_NAME} | grep "BeikeYun")" != "" ]]; then
    MYDTB_FILE="rockchip"
    MYBOOT_VMLINUZ="Image"
elif [[ "$(echo ${MYDEVICE_NAME} | grep "V-Plus Cloud")" != "" ]]; then
    MYDTB_FILE="allwinner"
    MYBOOT_VMLINUZ="zImage"
elif [[ -f "/etc/flippy-openwrt-release" ]]; then
    MYDTB_FILE="amlogic"
    MYBOOT_VMLINUZ="zImage"
else
    die "Unknown device: [ ${MYDEVICE_NAME} ], Not supported."
fi
echo -e "Current device: ${MYDEVICE_NAME} [${MYDTB_FILE}]"
sleep 3

EMMC_NAME=$(lsblk -l -o NAME | grep -oE '(mmcblk[0-9]?boot0)' | sed "s/boot0//g")
P4_PATH="/mnt/${EMMC_NAME}p4"

# Move kernel related files to the ${P4_PATH} directory
mv -f /tmp/upload/* ${P4_PATH}/ 2>/dev/null && sync
mv -f ${P4_PATH}/.tmp_upload/* ${P4_PATH}/ 2>/dev/null && sync

if  [ $( ls ${P4_PATH}/*.tar.gz -l 2>/dev/null | grep "^-" | wc -l ) -ge 3 ]; then

    if  [ $( ls ${P4_PATH}/boot-*.tar.gz -l 2>/dev/null | grep "^-" | wc -l ) -ge 1 ]; then
        build_boot=$( ls ${P4_PATH}/boot-*.tar.gz | head -n 1 ) && build_boot=${build_boot##*/}
        echo -e "Update using [ ${build_boot} ] files. Please wait a moment ..."
        flippy_version=${build_boot/boot-/} && flippy_version=${flippy_version/.tar.gz/}
        kernel_version=$(echo ${flippy_version} | grep -oE '^[1-9].[0-9]{1,3}.[0-9]+')
        kernel_vermaj=$(echo ${kernel_version} | grep -oE '^[1-9].[0-9]{1,3}')
        k510_ver=${kernel_vermaj%%.*}
        k510_maj=${kernel_vermaj##*.}
        if  [ ${k510_ver} -eq "5" ]; then
            if  [ "${k510_maj}" -ge "10" ]; then
                K510=1
            else
                K510=0
            fi
        elif [ ${k510_ver} -gt "5" ]; then
            K510=1
        else
            K510=0
        fi
    else
        die "Have no boot-*.tar.gz file found in the ${P4_PATH} directory."
    fi

    if  [[ -f ${P4_PATH}/dtb-${MYDTB_FILE}-${flippy_version}.tar.gz ]]; then
        build_dtb="dtb-${MYDTB_FILE}-${flippy_version}.tar.gz"
    else
        die "Have no dtb-${MYDTB_FILE}-${flippy_version}.tar.gz file."
    fi

    if  [ -f ${P4_PATH}/modules-${flippy_version}.tar.gz ]; then
        build_modules="modules-${flippy_version}.tar.gz"
    else
        die "Have no modules-*.tar.gz file found in the ${P4_PATH} directory."
    fi

    echo -e " \
    Try to using this files to update the kernel: \n \
    build_boot: ${build_boot} \n \
    build_dtb: ${build_dtb} \n \
    build_modules: ${build_modules} \n \
    flippy_version: ${flippy_version} \n \
    kernel_version: ${kernel_version} \n \
    K510: ${K510}"

else
    echo -e "Please upload the kernel files."
    echo -e "Upload method: system menu → Amlogic Service → Manually Upload Update"
    echo -e "Specify method: Place the kernel file in [ /mnt/${EMMC_NAME}p4/ ]"
    echo -e "After upload the kernel file, run again."
    exit 1
fi

MODULES_OLD=$(ls /lib/modules/ 2>/dev/null)
VERSION_OLD=$(echo ${MODULES_OLD} | grep -oE '^[1-9].[0-9]{1,3}' 2>/dev/null)
VERSION_ver=${VERSION_OLD%%.*}
VERSION_maj=${VERSION_OLD##*.}
if  [ ${VERSION_ver} -eq "5" ]; then
    if  [ "${VERSION_maj}" -ge "10" ]; then
        V510=1
    else
        V510=0
    fi
elif [ ${VERSION_ver} -gt "5" ]; then
    V510=1
else
    V510=0
fi

# Check version consistency from amlogic s9xxx
if [[ "${V510}" -lt "${K510}" && "${MYDTB_FILE}" == "amlogic" ]]; then
    echo -e "Update to kernel 5.10 or higher and install U-BOOT."
    if [ -f "/etc/flippy-openwrt-release" ]; then
        # U-BOOT adaptation
        source /etc/flippy-openwrt-release 2>/dev/null
        SOC=${SOC}
        [ -n "${SOC}" ] || die "Unknown SOC, unable to update."
        case ${SOC} in
            s905x3) UBOOT_OVERLOAD="u-boot-x96maxplus.bin"
                    MAINLINE_UBOOT="x96maxplus-u-boot.bin.sd.bin" ;;
            s905x2) UBOOT_OVERLOAD="u-boot-x96max.bin"
                    MAINLINE_UBOOT="x96max-u-boot.bin.sd.bin" ;;
            s905x)  UBOOT_OVERLOAD="u-boot-p212.bin"
                    MAINLINE_UBOOT="" ;;
            s905w)  UBOOT_OVERLOAD="u-boot-s905x-s912.bin"
                    MAINLINE_UBOOT="" ;;
            s905d)  UBOOT_OVERLOAD="u-boot-n1.bin"
                    MAINLINE_UBOOT="" ;;
            s912)   UBOOT_OVERLOAD="u-boot-zyxq.bin"
                    MAINLINE_UBOOT="" ;;
            s922x)  UBOOT_OVERLOAD="u-boot-gtkingpro.bin"
                    MAINLINE_UBOOT="gtkingpro-u-boot.bin.sd.bin" ;;
            *)      die "Unknown SOC, unable to update to kernel 5.10 and above." ;;
        esac

        # Check ${UBOOT_OVERLOAD}
        if [[ -n "${UBOOT_OVERLOAD}" ]]; then
            if [[ ! -f "/boot/${UBOOT_OVERLOAD}" ]]; then
                echo -e "Try to download the ${UBOOT_OVERLOAD} file from the server."
                GITHUB_UBOOT_OVERLOAD="${GITHUB_RAW}/without_fip/${UBOOT_OVERLOAD}"
                #echo -e "UBOOT_OVERLOAD: ${GITHUB_UBOOT_OVERLOAD}"
                wget -c "${GITHUB_UBOOT_OVERLOAD}" -O "/boot/${UBOOT_OVERLOAD}" >/dev/null 2>&1 && sync
                if [[ "$?" -eq "0" && -f "/boot/${UBOOT_OVERLOAD}" ]]; then
                    echo -e "The ${UBOOT_OVERLOAD} file download is complete."
                else
                    die "The ${UBOOT_OVERLOAD} file download failed. please try again."
                fi
            else
                echo -e "The ${UBOOT_OVERLOAD} file has been found."
            fi
        else
            die "The 5.10 kernel cannot be used without UBOOT_OVERLOAD."
        fi

        # Check ${MAINLINE_UBOOT}
        if [[ -n "${MAINLINE_UBOOT}" ]]; then
            if [[ ! -f "/lib/u-boot/${MAINLINE_UBOOT}" ]]; then
                echo -e "Try to download the MAINLINE_UBOOT file from the server."
                GITHUB_MAINLINE_UBOOT="${GITHUB_RAW}/with_fip/${MAINLINE_UBOOT}"
                #echo -e "MAINLINE_UBOOT: ${GITHUB_MAINLINE_UBOOT}"
                [ -d "/lib/u-boot" ] || mkdir -p /lib/u-boot
                wget -c "${GITHUB_MAINLINE_UBOOT}" -O "/lib/u-boot/${MAINLINE_UBOOT}" >/dev/null 2>&1 && sync
                if [[ "$?" -eq "0" && -f "/lib/u-boot/${MAINLINE_UBOOT}" ]]; then
                    echo -e "The MAINLINE_UBOOT file download is complete."
                else
                    die "The MAINLINE_UBOOT file download failed. please try again."
                fi
            fi
        fi
    else
        die "The /etc/flippy-openwrt-release file is missing and cannot be update."
    fi

    # Copy u-boot.ext and u-boot.emmc
    if [ -f "/boot/${UBOOT_OVERLOAD}" ]; then
        cp -f "/boot/${UBOOT_OVERLOAD}" /boot/u-boot.ext && sync && chmod +x /boot/u-boot.ext
        cp -f "/boot/${UBOOT_OVERLOAD}" /boot/u-boot.emmc && sync && chmod +x /boot/u-boot.emmc
        echo -e "The ${UBOOT_OVERLOAD} file copy is complete."
    else
        die "The UBOOT_OVERLOAD file is missing and cannot be update."
    fi

    # Write Mainline bootloader
    if [ -f "/lib/u-boot/${MAINLINE_UBOOT}" ]; then
        echo -e "Write Mainline bootloader: [ ${MAINLINE_UBOOT} ] to [ /dev/${EMMC_NAME} ]"
        dd if=/lib/u-boot/${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=1 count=442 conv=fsync
        dd if=/lib/u-boot/${MAINLINE_UBOOT} of=/dev/${EMMC_NAME} bs=512 skip=1 seek=1 conv=fsync
        echo -e "The MAINLINE_UBOOT file write is complete."
    fi
fi

echo -e "Unpack [ ${flippy_version} ] related files ..."

# 01. for /boot five files
rm -f /boot/config-* /boot/initrd.img-* /boot/System.map-* /boot/uInitrd-* /boot/vmlinuz-* 2>/dev/null && sync
rm -f /boot/uInitrd /boot/zImage /boot/Image 2>/dev/null && sync
tar -xzf ${P4_PATH}/${build_boot} -C /boot && sync

if [[ -f "/boot/uInitrd-${flippy_version}" ]]; then
    i=1
    max_try=10
    while [ "${i}" -le "${max_try}" ]; do
        cp -f /boot/uInitrd-${flippy_version} /boot/uInitrd 2>/dev/null && sync
        uInitrd_original=$(md5sum /boot/uInitrd-${flippy_version} | awk '{print $1}')
        uInitrd_new=$(md5sum /boot/uInitrd | awk '{print $1}')
        if [[ "${uInitrd_original}" == "${uInitrd_new}" ]]; then
            echo -e "Unpack [ /boot/uInitrd ] complete."
            break
        else
            rm -f /boot/uInitrd && sync
            let i++
            continue
        fi
    done
    [ "${i}" -eq "10" ] && die "/boot/uInitrd-${flippy_version} file copy failed."
else
    die "/boot/uInitrd-${flippy_version} file is missing."
fi

if [[ -f "/boot/vmlinuz-${flippy_version}" ]]; then
    i=1
    max_try=10
    while [ "${i}" -le "${max_try}" ]; do
        cp -f /boot/vmlinuz-${flippy_version} /boot/${MYBOOT_VMLINUZ} 2>/dev/null && sync
        vmlinuz_original=$(md5sum /boot/vmlinuz-${flippy_version} | awk '{print $1}')
        vmlinuz_new=$(md5sum /boot/${MYBOOT_VMLINUZ} | awk '{print $1}')
        if [[ "${vmlinuz_original}" == "${vmlinuz_new}" ]]; then
            echo -e "Unpack [ /boot/${MYBOOT_VMLINUZ} ] complete."
            break
        else
            rm -f /boot/${MYBOOT_VMLINUZ} && sync
            let i++
            continue
        fi
    done
    [ "${i}" -eq "10" ] && die "/boot/vmlinuz-${flippy_version} file copy failed."
else
    die "/boot/vmlinuz-${flippy_version} file is missing."
fi

[ -f "/boot/config-${flippy_version}" ] || die "/boot/config-${flippy_version} file is missing."
[ -f "/boot/System.map-${flippy_version}" ] || die "/boot/System.map-${flippy_version} file is missing."

echo -e "01. Unpack [ ${build_boot} ] complete."
sleep 3

# 02 for /boot/dtb/${MYDTB_FILE}/*
[ -d /boot/dtb/${MYDTB_FILE} ] || mkdir -p /boot/dtb/${MYDTB_FILE}
if [[ "${MYDTB_FILE}" == "rockchip" ]]; then
    mkdir -p /boot/dtb-${flippy_version}/${MYDTB_FILE}
    ln -sf /boot/dtb-${flippy_version} /boot/dtb
fi
tar -xzf ${P4_PATH}/${build_dtb} -C /boot/dtb/${MYDTB_FILE} && sync
[ "$( ls /boot/dtb/${MYDTB_FILE} -l 2>/dev/null | grep "^-" | wc -l )" -ge "1" ] || die "/boot/dtb/${MYDTB_FILE} file is missing."
echo -e "02. Unpack [ ${build_dtb} ] complete."
sleep 3

# 03 for /lib/modules/*
rm -rf /lib/modules/* 2>/dev/null && sync
tar -xzf ${P4_PATH}/${build_modules} -C /lib/modules && sync
    cd /lib/modules/${flippy_version}/
    rm -f *.ko 2>/dev/null
    find ./ -type f -name '*.ko' -exec ln -s {} ./ \;
    sync && sleep 3
        x=$( ls *.ko -l 2>/dev/null | grep "^l" | wc -l )
        if [ "${x}" -eq "0" ]; then
            die "Error *.ko Files not found."
        fi
echo -e "03. Unpack [ ${build_modules} ] complete."
sleep 3

rm -rf ${P4_PATH}/dtb-*.tar.gz ${P4_PATH}/boot-*.tar.gz ${P4_PATH}/modules-*.tar.gz 2>/dev/null
sync

sed -i '/KERNEL_VERSION/d' /etc/flippy-openwrt-release 2>/dev/null
echo "KERNEL_VERSION='${kernel_version}'" >> /etc/flippy-openwrt-release 2>/dev/null

sed -i '/K510/d' /etc/flippy-openwrt-release 2>/dev/null
echo "K510='${K510}'" >> /etc/flippy-openwrt-release 2>/dev/null

sed -i "s/ Kernel.*/ Kernel: ${flippy_version}/g" /etc/banner 2>/dev/null

sync
wait

echo "Successfully updated, automatic restarting..."
sleep 3
reboot
exit 0

